/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#ifndef AT32_BOOTLOADER_UART_PROTOCOL_H
#define AT32_BOOTLOADER_UART_PROTOCOL_H

#include <stdint.h>
/**NOTE
 * 注意 1：AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32A403Axx
 * 这几个系列在使用 Get Commands 和 Get Device ID 命令前要先发送 Set ISP 命令。如果对于其它不
 * 支持 Set ISP 命令的系列发送 Set ISP 命令，设备端会回复 NACK，主机可以忽略此 NACK， 继续后面的命令操作
 */
enum AT32_Bootloader_Commands
{
    /**
     * 当使用UART编程模式时，Bootloader启动之后会检测UARTx Rx引脚，等待接收0x7F数据帧：一个
     * 起始位，0x7F数据位，奇偶校验位和一个停止位。通过Systick定时器测量该数据帧，计算出UARTx
     * 使用的波特率，再通过UARTx响应主机0x79，表示连接成功，此时微控制器端等待接收主机命令。
     */
    AT32_CMD_SYNC = 0x7F,
    AT32_CMD_ACK = 0x79,
    AT32_CMD_NACK = 0x1F,
    AT32_CMD_Set_ISP = 0xFA,                     /* 设置上位机识别编号 AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32A403Axx */
    AT32_CMD_Get_Commands = 0x00,                /* 获取设备支持命令列表 AT32F403xx，AT32F413xx(1)，AT32F415xx(1)，AT32F403Axx(1)，AT32F407xx(1)，AT32F421xx(1)，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx， AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx,AT32A423Axx*/
    AT32_CMD_Get_Version = 0x01,                 /* 获取 bootloader 版本号 AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Get_Device_ID = 0x02,               /* 获取设备 ID 号，可用于判断型号AT32F403xx，AT32F413xx(1)，AT32F415xx(1)，AT32F403Axx(1)，AT32F407xx(1)，AT32F421xx(1)，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx,AT32A423Axx*/
    AT32_CMD_Read_memory = 0x11,                 /* 读取存储器指定地址的数据AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Jump = 0x21,                        /* 跳转到指定的存储器地址执行程序AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Write_memory = 0x31,                /* 写数据到存储器的指定地址AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Erase = 0x44,                       /* 擦除存储器 AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Erase_and_program_protect = 0x63,   /* 开启擦写保护 AT32F403xx，AT32F413xx，AT32F415xx，protect AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Erase_and_program_unprotect = 0x73, /* 关闭擦写保护 AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Access_Protect = 0x82,              /* 开启访问保护 AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Access_Unprotect = 0x92,            /* 关闭访问保护 AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Firmware_CRC = 0xAC,                /* 计算指定 sector CRC AT32F403xx，AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Enable_SPIM = 0xB3,                 /* 使能外部存储器 AT32F403xx，AT32F413xx， AT32F403Axx，AT32F407xx，AT32A403Axx*/
    AT32_CMD_Enable_sLib = 0xD0,                 /* 使能 sLib 功能 AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Disable_sLib = 0xD1,                /* 解除 sLib 功能 AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Get_sLib_Status = 0xD2,             /* 获取 sLib 状态 AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_SPIM_Remap = 0xD3,                  /* SPIM IO pin 脚重映射 AT32F413xx， AT32F403Axx，AT32F407xx，AT32A403Axx*/
    AT32_CMD_Reset_Device = 0xD4,                /* 复位设备 AT32F413xx，AT32F415xx，AT32F403Axx，AT32F407xx，AT32F421xx，AT32F435xx，AT32F437xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx，AT32A403Axx, AT32A423Axx*/
    AT32_CMD_Advanced_Access_Protect = 0xD6,     /* 使能高级访问保护 AT32F415xx， AT32F421xx，AT32F425xx，AT32F423xx，AT32L021xx，AT32F405xx，AT32F402xx, AT32A423Axx*/
};
struct at32_bl_cmds{
    uint8_t value;
    const char *name;
    const char *usage;
};
#define AT32_CMD_PACK_SIZE 4096
struct at32_bup_pack{
    uint8_t cmd;
    uint8_t cmd2;
    uint8_t len;
    uint8_t crc;
    uint8_t data[AT32_CMD_PACK_SIZE];
};
typedef struct at32_bootloader_uart_protocol at32_bup_t;
struct at32_bootloader_uart_protocol{
    int synced;
    int fcom;
    int p_comport;
    int p_readfile;
    int p_writefile;
    uint8_t targetVersion;
    uint8_t targetCmds[256];
    uint8_t targetCmdCount;
    uint8_t targetProtocolVersion;
    uint16_t BID;
    uint64_t deviceID;
    int (*clearIo)(void);
    int (*hardwareReset)(void);
    int (*restToIspMode)(void);
    int (*read)(uint8_t *data, uint16_t len);
    int (*write)(uint8_t *data, uint16_t len);
    void (*delay_ms)(uint32_t ms);
    int (*write_cmd)(at32_bup_t *b, uint8_t cmd);
    int (*write_data)(at32_bup_t *b, uint8_t *data, uint16_t len);
};
int at32_show_match_cmds(uint8_t *cmdValues, int len);
uint8_t at32_wait_ack(at32_bup_t *b);
int at32_sync(at32_bup_t *b);
int at32_set_isp(at32_bup_t *b);
int at32_get_commands(at32_bup_t *b);
int at32_get_version(at32_bup_t *b);
int at32_get_device_id(at32_bup_t *b);
int at32_read_memory(at32_bup_t *b, uint32_t addr, uint8_t *buf, uint8_t len);
int at32_jump_to_address(at32_bup_t *b, uint32_t addr);
int at32_write_memory(at32_bup_t *b, uint32_t addr, uint8_t *buf, uint32_t len);
int at32_erase_sector(at32_bup_t *b, uint16_t count, uint16_t *sectors);
int at32_earase_block(at32_bup_t *b, uint32_t blockAddr);
int at32_erase_bank(at32_bup_t *b, uint8_t type);
int at32_erase_and_program_protect(at32_bup_t *b, uint16_t secotorCount, uint8_t *sectors);
int at32_erase_and_program_unprotect(at32_bup_t *b);
int at32_access_protect(at32_bup_t *b);
int at32_access_unprotect(at32_bup_t *b);
int at32_firmware_crc(at32_bup_t *b, uint32_t startAddress, uint16_t sectorCount, uint32_t *crc);
int at32_enable_SPIM(at32_bup_t *b, uint8_t type, uint32_t size, uint32_t fda);
int at32_enable_sLib(at32_bup_t *b, uint32_t password, uint16_t start, uint16_t data, uint16_t end);
int at32_disable_sLib(at32_bup_t *b, uint32_t password);
int at32_get_sLib_status(at32_bup_t *b, uint8_t *status);
int at32_SPIM_Remap(at32_bup_t *b, uint8_t remap);
int at32_reset_device(at32_bup_t *b);
int at32_advanced_Access_protect(at32_bup_t *b, uint8_t *flag);

#endif
